/*
 * Copyright 2002-2004 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package com.googlecode.lookie.platform;

import java.io.IOException;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.richclient.application.ApplicationWindow;
import org.springframework.richclient.application.config.ApplicationLifecycleAdvisor;
import org.springframework.richclient.application.config.ApplicationWindowConfigurer;
import org.springframework.richclient.application.support.ApplicationWindowCommandManager;
import org.springframework.richclient.command.CommandGroup;
import org.springframework.richclient.settings.Settings;

import com.googlecode.lookie.platform.osgi.LifecycleHook;
import com.googlecode.lookie.platform.settings.LookieSettingsManager;
import com.googlecode.lookie.platform.settings.SettingsIds;
import com.googlecode.lookie.platform.totd.TipOfTheDayBox;

/*
 * Custom application lifecycle implementation that configures the sample app at well defined points
 * within its lifecycle.
 * 
 * @author Keith Donald
 */
public class PlatformLifecycleAdvisor
    extends ApplicationLifecycleAdvisor
{

    private final Log logger = LogFactory.getLog( getClass() );

    private List<LifecycleHook> hooks;

    @Autowired
    private TipOfTheDayBox tipOfTheDayBox;

    @Autowired
    private LookieSettingsManager settingsManager;

    public void setHooks( List<LifecycleHook> hooks )
    {
        this.hooks = hooks;
    }

    /**
     * This method is called prior to the opening of an application window. Note at this point the window control has
     * not been created. This hook allows programmatic control over the configuration of the window (by setting
     * properties on the configurer) and it provides a hook where code that needs to be executed prior to the window
     * opening can be plugged in (like a startup wizard, for example).
     *
     * @param configurer The application window configurer
     */
    public void onPreWindowOpen( ApplicationWindowConfigurer configurer )
    {

        // If you override this method, it is critical to allow the superclass
        // implementation to run as well.
        super.onPreWindowOpen( configurer );

        // Uncomment to hide the menubar, toolbar, or alter window size...
        // configurer.setShowMenuBar(false);
        // configurer.setShowToolBar(false);
        // configurer.setInitialSize(new Dimension(640, 480));
    }

    /**
     * Called just after the command context has been internalized. At this point, all the commands for the window have
     * been created and are available for use. If you need to force the execution of a command prior to the display of
     * an application window (like a login command), this is where you'd do it.
     *
     * @param window The window who's commands have just been created
     */
    public void onCommandsCreated( ApplicationWindow window )
    {
        if ( logger.isInfoEnabled() )
        {
            logger.info( "onCommandsCreated( windowNumber=" + window.getNumber() + " )" );
        }
    }

    /**
     * Called after the actual window control has been created.
     *
     * @param window The window being processed
     */
    public void onWindowCreated( ApplicationWindow window )
    {
        if ( logger.isInfoEnabled() )
        {
            logger.info( "onWindowCreated( windowNumber=" + window.getNumber() + " )" );
        }
    }

    /**
     * Called immediately after making the window visible.
     *
     * @param window The window being processed
     */
    public void onWindowOpened( ApplicationWindow window )
    {
        if ( logger.isInfoEnabled() )
        {
            logger.info( "onWindowOpened( windowNumber=" + window.getNumber() + " )" );
        }
    }

    /**
     * Called when the window is being closed. This hook allows control over whether the window is allowed to close. By
     * returning false from this method, the window will not be closed.
     *
     * @return boolean indicator if window should be closed. <code>true</code> to allow the close, <code>false</code> to
     *         prevent the close.
     */
    public boolean onPreWindowClose( ApplicationWindow window )
    {
        if ( logger.isInfoEnabled() )
        {
            logger.info( "onPreWindowClose( windowNumber=" + window.getNumber() + " )" );
        }
        return true;
    }

    public void onPostStartup()
    {
        if ( logger.isInfoEnabled() )
        {
            logger.info( "onPostStartup()" );
        }

        Settings userSettings = settingsManager.getUserSettings();
        boolean showTips = userSettings.getBoolean( SettingsIds.SHOW_TIPS );

        if ( showTips )
        {
            tipOfTheDayBox.setShowTipsSelected( showTips );
            tipOfTheDayBox.display( getOpeningWindow().getControl() );
            showTips = tipOfTheDayBox.isShowTipsSelected();
            userSettings.setBoolean( SettingsIds.SHOW_TIPS, showTips );
        }

        for ( LifecycleHook hook : hooks )
        {
            hook.onPostStartup();
        }
    }

    public void onPreStartup()
    {
        if ( logger.isInfoEnabled() )
        {
            logger.info( "onPreStartup()" );
        }

        for ( LifecycleHook hook : hooks )
        {
            hook.onPreStartup();
        }
    }

    public void onShutdown()
    {
        if ( logger.isInfoEnabled() )
        {
            logger.info( "onShutdown()" );
        }

        Settings userSettings = settingsManager.getUserSettings();

        try
        {
            userSettings.save();
        }
        catch ( IOException e )
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        for ( LifecycleHook hook : hooks )
        {
            hook.onShutdown();
        }
    }

    public ApplicationWindowCommandManager createWindowCommandManager()
    {
        return (ApplicationWindowCommandManager) getApplication().getApplicationContext()
            .getBean( "windowCommandManager" );
    }

    public CommandGroup getMenuBarCommandGroup()
    {
        return getCommandGroup( "menuBar" );
    }

    public CommandGroup getToolBarCommandGroup()
    {
        return getCommandGroup( "toolBar" );
    }

    protected CommandGroup getCommandGroup( String name )
    {
        if ( name == null )
        {
            return null;
        }
        return (CommandGroup) getApplication().getApplicationContext().getBean( name );
    }

    public ApplicationWindow getWindow()
    {
        return getOpeningWindow();
    }

    //    private String windowCommandManagerBeanName;
    //
    //    private String toolBarBeanName;
    //
    //    private String menuBarBeanName;
    //
    //    private String windowCommandBarDefinitions;
    //
    //    private ConfigurableListableBeanFactory openingWindowCommandBarFactory;
    //
    //    /** Set of child command contexts created - used to bridge application events. */
    //    private ArrayList childContexts = new ArrayList();
    //
    //    public void setWindowCommandBarDefinitions(String commandBarDefinitionLocation) {
    //        this.windowCommandBarDefinitions = commandBarDefinitionLocation;
    //    }
    //
    //    public void setWindowCommandManagerBeanName(String commandManagerBeanName) {
    //        this.windowCommandManagerBeanName = commandManagerBeanName;
    //    }
    //
    //    public void setMenubarBeanName(String menubarBeanName) {
    //        this.menuBarBeanName = menubarBeanName;
    //    }
    //
    //    public void setToolbarBeanName(String toolbarBeanName) {
    //        this.toolBarBeanName = toolbarBeanName;
    //    }
    //
    //    public ApplicationWindowCommandManager createWindowCommandManager() {
    //        initNewWindowCommandBarFactory();
    //        if (windowCommandManagerBeanName == null || !getCommandBarFactory().containsBean(windowCommandManagerBeanName)) {
    //            return new ApplicationWindowCommandManager();
    //        }
    //        return (ApplicationWindowCommandManager)getCommandBarFactory().getBean(windowCommandManagerBeanName,
    //                ApplicationWindowCommandManager.class);
    //    }
    //
    //    protected void initNewWindowCommandBarFactory() {
    //    	if (windowCommandBarDefinitions != null) {
    //    		// Install our own application context so we can register needed post-processors
    //    		final CommandBarApplicationContext commandBarContext =
    //    			new CommandBarApplicationContext(windowCommandBarDefinitions);
    //    		addChildCommandContext(commandBarContext);
    //    		this.openingWindowCommandBarFactory = commandBarContext.getBeanFactory();
    //    	} else {
    //    		this.openingWindowCommandBarFactory = new DefaultListableBeanFactory();
    //    	}
    //    }
    //
    //    protected ConfigurableListableBeanFactory getCommandBarFactory() {
    //        return openingWindowCommandBarFactory;
    //    }
    //
    //    public CommandGroup getMenuBarCommandGroup() {
    //        CommandGroup menuBarCommandGroup = getCommandGroup(menuBarBeanName);
    //        return menuBarCommandGroup != null ? menuBarCommandGroup : super.getMenuBarCommandGroup();
    //    }
    //
    //    public CommandGroup getToolBarCommandGroup() {
    //        CommandGroup toolBarCommandGroup = getCommandGroup(toolBarBeanName);
    //        return toolBarCommandGroup != null ? toolBarCommandGroup : super.getToolBarCommandGroup();
    //    }
    //
    //    protected CommandGroup getCommandGroup(String name) {
    //        if (name == null || !getCommandBarFactory().containsBean(name)) {
    //            return null;
    //        }
    //        return (CommandGroup)getCommandBarFactory().getBean(name);
    //    }
    //
    //    /**
    //     * We need to deliver all application events down to the child command
    //     * contexts that have been created.
    //     * @param event to deliver
    //     */
    //    public void onApplicationEvent(ApplicationEvent event) {
    //        // Dispatch the event to all the child command contexts
    //        for( Iterator iter = getChildCommandContexts().iterator(); iter.hasNext(); ) {
    //            ApplicationContext ctx = (ApplicationContext) iter.next();
    //            ctx.publishEvent(event);
    //        }
    //    }
    //
    //    /**
    //     * Get all the child command contexts that have been created.
    //     * <p>
    //     * <em>Note, theactual collection is being returned - so be careful what you
    //     * do to it.</em>
    //     *
    //     * @return list of contexts
    //     */
    //    protected List getChildCommandContexts() {
    //        return childContexts;
    //    }
    //
    //    /**
    //     * Add a new child command context.
    //     * @param context
    //     */
    //    protected void addChildCommandContext( ApplicationContext context ) {
    //        childContexts.add( context );
    //    }
    //
    //    /**
    //     * Simple extension to allow us to inject our special bean post-processors
    //     * and control event publishing.
    //     */
    //    private class CommandBarApplicationContext extends ClassPathXmlApplicationContext {
    //
    //        /**
    //         * Constructor. Load bean definitions from the specified location.
    //         * @param location of bean definitions
    //         */
    //        public CommandBarApplicationContext(String location) {
    //            super( new String[] { location }, false, Application.instance().getApplicationContext() );
    //            refresh();
    //        }
    //
    //        protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {
    //    		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
    //    		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    //    		beanDefinitionReader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE);
    //
    //    		// Configure the bean definition reader with this context's
    //    		// resource loading environment.
    //    		beanDefinitionReader.setResourceLoader(this);
    //    		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    //
    //    		// Allow a subclass to provide custom initialization of the reader,
    //    		// then proceed with actually loading the bean definitions.
    //    		initBeanDefinitionReader(beanDefinitionReader);
    //    		loadBeanDefinitions(beanDefinitionReader);
    //    	}
    //
    //        /**
    //         * Install our bean post-processors.
    //         * @param beanFactory the bean factory used by the application context
    //         * @throws org.springframework.beans.BeansException in case of errors
    //         */
    //        protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    //            beanFactory.addBeanPostProcessor( new PlatformWindowSetter( getOpeningWindow() ) );
    //        }
    //
    //        /**
    //         * Publish an event in to this context.  Since we are always getting
    //         * notification from a parent context, this overriden implementation does
    //         * not dispatch up to the parent context, thus avoiding an infinite loop.
    //         */
    //        public void publishEvent(ApplicationEvent event) {
    //            // Temporarily disconnect our parent so the event publishing doesn't
    //            // result in an infinite loop.
    //            ApplicationContext parent = getParent();
    //            setParent(null);
    //            super.publishEvent(event);
    //            setParent(parent);
    //        }
    //    }

}
